// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
// SPDX-License-Identifier: MIT

package metrics

import (
	"fmt"
	"io/fs"
	"path/filepath"
	"strings"
	"uos-syslog-ng-exporter/internal/exporter"
	"uos-syslog-ng-exporter/pkg/utils"

	"github.com/go-kit/log/level"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/sirupsen/logrus"
)

func init() {
	exporter.Register(NewSyslogNGConfigFiles("syslog_ng_config_files_total",
		"Total number of configuration files in /etc/syslog-ng directory.",
		[]string{"directory", "extension"}))

	exporter.Register(NewSyslogNGConfigFileSize("syslog_ng_config_file_size_bytes",
		"Size of configuration files in bytes.",
		[]string{"file_path", "file_name"}))

	exporter.Register(NewSyslogNGConfigFileModified("syslog_ng_config_file_modified_timestamp",
		"Last modified timestamp of configuration files.",
		[]string{"file_path", "file_name"}))
}

// SyslogNGConfigFiles 配置文件的收集器
type SyslogNGConfigFiles struct {
	*SyslogNGCollector
	configPath string
}

// SyslogNGConfigFileSize 配置文件大小的收集器
type SyslogNGConfigFileSize struct {
	*SyslogNGCollector
	configPath string
}

// SyslogNGConfigFileModified 配置文件修改时间的收集器
type SyslogNGConfigFileModified struct {
	*SyslogNGCollector
	configPath string
}

// NewSyslogNGConfigFiles 创建一个新的配置文件数量收集器
func NewSyslogNGConfigFiles(fqname, help string, labels []string) *SyslogNGConfigFiles {
	return &SyslogNGConfigFiles{
		SyslogNGCollector: NewSyslogNGCollector(fqname, help, labels),
		configPath:        "/etc/syslog-ng",
	}
}

// NewSyslogNGConfigFileSize 创建一个新的配置文件大小收集器
func NewSyslogNGConfigFileSize(fqname, help string, labels []string) *SyslogNGConfigFileSize {
	return &SyslogNGConfigFileSize{
		SyslogNGCollector: NewSyslogNGCollector(fqname, help, labels),
		configPath:        "/etc/syslog-ng",
	}
}

// NewSyslogNGConfigFileModified 创建一个新的配置文件修改时间收集器
func NewSyslogNGConfigFileModified(fqname, help string, labels []string) *SyslogNGConfigFileModified {
	return &SyslogNGConfigFileModified{
		SyslogNGCollector: NewSyslogNGCollector(fqname, help, labels),
		configPath:        "/etc/syslog-ng",
	}
}

// scanConfigFiles 扫描配置文件目录
func (c *SyslogNGCollector) scanConfigFiles(configPath string) ([]FileInfo, error) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	logrus.Debugf("Scanning config files in directory: %s", configPath)

	// 检查目录是否存在
	if !utils.FileExists(configPath) {
		logrus.Warnf("Config directory does not exist: %s", configPath)
		return nil, fmt.Errorf("config directory does not exist: %s", configPath)
	}

	var files []FileInfo

	err := filepath.Walk(configPath, func(path string, info fs.FileInfo, err error) error {
		if err != nil {
			level.Error(c.logger).Log("msg", "Error walking path", "path", path, "err", err)
			return nil // 继续遍历其他文件
		}

		// 跳过目录
		if info.IsDir() {
			return nil
		}

		// 只收集配置文件（常见的配置文件扩展名）
		ext := strings.ToLower(filepath.Ext(path))
		if isConfigFile(ext) {
			relPath, _ := filepath.Rel(configPath, path)
			files = append(files, FileInfo{
				Path:         path,
				RelativePath: relPath,
				Name:         info.Name(),
				Size:         info.Size(),
				Modified:     info.ModTime().Unix(),
				Extension:    ext,
			})
			logrus.Debugf("Found config file: %s (size: %d, modified: %d)", path, info.Size(), info.ModTime().Unix())
		}

		return nil
	})

	if err != nil {
		level.Error(c.logger).Log("msg", "Error scanning config directory", "path", configPath, "err", err)
		return nil, fmt.Errorf("error scanning config directory: %v", err)
	}

	logrus.Infof("Found %d configuration files in %s", len(files), configPath)
	return files, nil
}

// isConfigFile 判断是否为配置文件
func isConfigFile(ext string) bool {
	configExts := []string{".conf", ".config", ".cfg", ".ini", ".xml", ".json", ".yaml", ".yml"}
	for _, configExt := range configExts {
		if ext == configExt {
			return true
		}
	}
	return false
}

// FileInfo 文件信息结构
type FileInfo struct {
	Path         string
	RelativePath string
	Name         string
	Size         int64
	Modified     int64
	Extension    string
}

// Describe 实现 SyslogNGConfigFiles 的 Describe 方法
func (c *SyslogNGConfigFiles) Describe(ch chan<- *prometheus.Desc) {
	ch <- c.baseMetrics.desc
}

// Describe 实现 SyslogNGConfigFileSize 的 Describe 方法
func (c *SyslogNGConfigFileSize) Describe(ch chan<- *prometheus.Desc) {
	ch <- c.baseMetrics.desc
}

// Describe 实现 SyslogNGConfigFileModified 的 Describe 方法
func (c *SyslogNGConfigFileModified) Describe(ch chan<- *prometheus.Desc) {
	ch <- c.baseMetrics.desc
}

// Collect 实现 SyslogNGConfigFiles 的 Collect 方法
func (c *SyslogNGConfigFiles) Collect(ch chan<- prometheus.Metric) {
	files, err := c.scanConfigFiles(c.configPath)
	if err != nil {
		level.Error(c.logger).Log("msg", "Error scanning config files", "err", err)
		return
	}

	// 按扩展名分组统计
	extCount := make(map[string]int)
	for _, file := range files {
		extCount[file.Extension]++
	}

	// 输出总数
	c.baseMetrics.collect(ch, float64(len(files)), []string{c.configPath, "total"})

	// 按扩展名输出
	for ext, count := range extCount {
		c.baseMetrics.collect(ch, float64(count), []string{c.configPath, ext})
	}
}

// Collect 实现 SyslogNGConfigFileSize 的 Collect 方法
func (c *SyslogNGConfigFileSize) Collect(ch chan<- prometheus.Metric) {
	files, err := c.scanConfigFiles(c.configPath)
	if err != nil {
		level.Error(c.logger).Log("msg", "Error scanning config files", "err", err)
		return
	}

	for _, file := range files {
		c.baseMetrics.collect(ch, float64(file.Size), []string{file.RelativePath, file.Name})
	}
}

// Collect 实现 SyslogNGConfigFileModified 的 Collect 方法
func (c *SyslogNGConfigFileModified) Collect(ch chan<- prometheus.Metric) {
	files, err := c.scanConfigFiles(c.configPath)
	if err != nil {
		level.Error(c.logger).Log("msg", "Error scanning config files", "err", err)
		return
	}

	for _, file := range files {
		c.baseMetrics.collect(ch, float64(file.Modified), []string{file.RelativePath, file.Name})
	}
}
